﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using S7.Net;
using S7PlcDataCollector.Client.Forms;
using S7PlcDataCollector.Models;
using S7PlcDataCollector.Service;
using S7PlcDataCollector.Service.PlcLink;
using ZbSkin.Frm;
using ZbSkin.Tools;

namespace S7PlcDataCollector.Client.Controls
{
    public partial class PlcListControl : PageControl
    {
        private readonly SynchronizationContext _context;
        private static readonly int LinkStateColumn = 6;
        private readonly List<S7PlcEntityInfo> _s7PlcEntityInfoList;

        public PlcListControl()
        {
            InitializeComponent();
            _context = SynchronizationContext.Current;
            _s7PlcEntityInfoList = new List<S7PlcEntityInfo>();
        }

        private void PlcListControl_Load(object sender, EventArgs e)
        {
            DataGridViewHelper.SetCommonStyle(dataGridView);
            UpdateDataGridView();
            ResizeControls();
        }

        private void PlcListControl_Resize(object sender, EventArgs e)
        {
            ResizeControls();
        }

        private void ResizeControls()
        {
            SetRegion();

            dataGridView.Width = ClientSize.Width - 40;
            dataGridView.Height = ClientSize.Height - dataGridView.Top - btnAdd.Height * 2;
            dataGridView.Left = 20;
            btnAdd.Top = ClientSize.Height - (int) (btnAdd.Height * 1.5f);
            btnDel.Top = btnAdd.Top;
            btnEdit.Top = btnAdd.Top;
        }

        protected override void ShowControl()
        {
            base.ShowControl();
            S7PlcDataCollectorService.Instance.LinkStateChangeEvent += OnLinkStateChange;
        }

        protected override void HideControl()
        {
            S7PlcDataCollectorService.Instance.LinkStateChangeEvent -= OnLinkStateChange;
            base.HideControl();
        }

        private void dataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            UpdatePlcDevice();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            var form = new FrmPlcDeviceSetup() {Owner = ParentForm};
            if (form.ShowDialog() == DialogResult.OK)
            {
                UpdateDataGridView();
            }
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            UpdatePlcDevice();
        }

        private void btnDel_Click(object sender, EventArgs e)
        {
            var model = (dataGridView.CurrentRow?.DataBoundItem as S7PlcEntityInfo)?.Model;
            if (model == null)
            {
                return;
            }

            var text = $@"确定要删除PLC设备[{model.TypeEnum} @ {model.Ip}.{model.Port}]吗？";
            if (!MessageBoxEx.Question(text, ParentForm))
            {
                return;
            }

            if (S7PlcDataCollectorService.Instance.DeleteS7PlcEntity(model))
            {
                S7PlcDataCollectorService.Instance.RemovePlcLink(model);
                UpdateDataGridView();
            }
            else
            {
                MessageBoxEx.Warning(@"删除PLC设备失败");
            }
        }

        private void UpdatePlcDevice()
        {
            var model = (dataGridView.CurrentRow?.DataBoundItem as S7PlcEntityInfo)?.Model;
            if (model == null)
            {
                return;
            }

            var form = new FrmPlcDeviceSetup(model) {Owner = ParentForm};
            if (form.ShowDialog() == DialogResult.OK)
            {
                UpdateDataGridView();
            }
        }

        private void UpdateDataGridView()
        {
            dataGridView.DataSource = null;

            _s7PlcEntityInfoList.Clear();
            var index = 0;
            var models = S7PlcDataCollectorService.Instance.GetS7PlcEntityList();
            foreach (var model in models)
            {
                _s7PlcEntityInfoList.Add(new S7PlcEntityInfo()
                {
                    Index = ++index,
                    Model = model,
                    LinkState = S7PlcDataCollectorService.Instance.GetLinkState(model.Rid)
                });
            }

            dataGridView.AutoGenerateColumns = false;
            dataGridView.DataSource = _s7PlcEntityInfoList;
        }

        private void OnLinkStateChange(S7PlcEntity plcEntity, PlcLinkState linkState)
        {
            if (plcEntity == null || plcEntity.Rid <= 0)
            {
                return;
            }

            var index = -1;
            for (var i = 0; i < _s7PlcEntityInfoList.Count; i++)
            {
                if (_s7PlcEntityInfoList[i].Rid == plcEntity.Rid)
                {
                    index = i;
                    break;
                }
            }

            if (index < 0 || _s7PlcEntityInfoList[index].LinkState == linkState)
            {
                return;
            }

            _s7PlcEntityInfoList[index].LinkState = linkState;
            _context?.Post((state) =>
            {
                var rowIndex = (int) state;
                dataGridView.UpdateCellValue(LinkStateColumn, rowIndex);
            }, index);
        }

        private class S7PlcEntityInfo
        {
            // ReSharper disable once UnusedAutoPropertyAccessor.Local
            public int Index { get; set; }
            public int Rid => Model?.Rid ?? 0;

            // ReSharper disable once UnusedMember.Local
            public CpuType Type => Model?.TypeEnum ?? CpuType.S7200;

            // ReSharper disable once UnusedMember.Local
            public string Ip => Model?.Ip;

            // ReSharper disable once UnusedMember.Local
            public int Port => Model?.Port ?? 0;

            // ReSharper disable once UnusedMember.Local
            public int Rack => Model?.Rack ?? 0;

            // ReSharper disable once UnusedMember.Local
            public int Slot => Model?.Slot ?? 0;
            public S7PlcEntity Model { get; set; }
            public PlcLinkState LinkState { get; set; } = PlcLinkState.Linking;
        }
    }
}
